﻿using AutoMapper;
using MediatR;
using WeatherHistory.Data.Repositories.Interfaces;
using WeatherHistory.Shared.Exceptions;

namespace WeatherHistory.Api.CommandsQueries.Commands.Regions.Update;

public class UpdateRegionsCommandHandler : IRequestHandler<UpdateRegionsCommandRequest, UpdateRegionsCommandResponse>
{
    private readonly IMapper _mapper;
    private readonly IRegionRepository _regionRepository;

    public UpdateRegionsCommandHandler(IMapper mapper, IRegionRepository regionRepository)
    {
        _mapper = mapper;
        _regionRepository = regionRepository;
    }

    public async Task<UpdateRegionsCommandResponse> Handle(UpdateRegionsCommandRequest request, CancellationToken cancellationToken)
    {
        var region = await _regionRepository.FirstOrDefaultAsync(x => x.Id == request.RegionId, cancellationToken);
        if (region == null) throw new NotFoundException($"Регион с id '{request.RegionId}' не найден");

        const double coordinatesComparisonTolerance = 0.000001;
        var regionExists = await _regionRepository.AnyAsync(x => Math.Abs(x.Latitude - request.Latitude) < coordinatesComparisonTolerance
                                                                 && Math.Abs(x.Longitude - request.Longitude) < coordinatesComparisonTolerance
                                                                 && request.RegionId != x.Id, cancellationToken);
        if (regionExists) throw new ConflictException("Регион с такими координатами уже существует");

        region.Latitude = request.Latitude;
        region.Longitude = request.Longitude;
        region.Name = request.Name;
        region.RegionTypeId = request.RegionType;

        if (request.ParentRegion != null)
        {
            var parentRegion = await _regionRepository.FirstOrDefaultAsync(x => x.Name == request.ParentRegion && x.Id != request.RegionId, cancellationToken);
            region.ParentRegionId = parentRegion?.Id;
            region.ParentRegion = parentRegion;
        }
        else
        {
            region.ParentRegionId = null;
            region.ParentRegion = null;
        }

        await _regionRepository.UpdateAsync(region, cancellationToken);
        return _mapper.Map<UpdateRegionsCommandResponse>(region);
    }
}